﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using System.IO;
using YasharEl.Infrastructure.ResourcesManagement.Managers;
using YasharEl.Infrastructure.Diagnostics.Logging;

namespace YasharEl.Infrastructure.ResourcesManagement.Providers
{
    /// <summary>
    /// Abstract File based Resource Provider.
    /// </summary>
    /// <remarks>
    /// This provider loads a resource file and generates a <see cref="ExtendedComponentResourceManager" /> populated
    /// with resources from the file.
    /// </remarks>
    public abstract class FileResourceProvider : ResourceProvider
    {
        #region Fields

        private string resourcePathName;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new default instance of the <see cref="FileResourceProvider"/> class.
        /// </summary>
        /// <param name="resourcePathName">Name of the resource path.</param>
        /// <param name="resourceBaseName">Name of the resource base.</param>
        protected FileResourceProvider(string resourcePathName, string resourceBaseName, ILogger<ResourceProvider> logger)
            : base(resourceBaseName, logger)
        {
            ValidateAndStoreParameters(resourcePathName);
        }

        #endregion

        #region Public Methods
        /// <summary>
        /// Create a Resource Manager to manage the resource for a file based resource provider
        /// </summary>
        /// <returns>A <see cref="ExtendedComponentResourceManager" /> instance</returns>
        /// <remarks>
        /// <para>This method makes a <see cref="ExtendedComponentResourceManager"/> instance publicly available
        /// based on the path name and base name retrieved during Initialisation</para>
        /// </remarks>
        public override ExtendedComponentResourceManager CreateResourceManager()
        {
            // Check for first time use of resource manager
            if (ResourceManager == null)
            {
                // Generate a Resource Manager
                ResourceManager = CreateFileResourceManager(resourcePathName, ResourceBaseName);
                ResourceManager.IgnoreCase = true;
            }
            return ResourceManager;
        }

        /// <summary>
        /// Creates the file resource manager.
        /// </summary>
        /// <returns>instance of the file resource manager type</returns>
        protected abstract ExtendedComponentResourceManager CreateFileResourceManager(string resourcePathName, string resourceBaseName);

        /// <summary>
        /// Gets the file resource extension.
        /// </summary>
        /// <returns>extension without the separator</returns>
        protected abstract string FindFileResourceExtension();
        #endregion

        #region Private Methods

        /// <summary>
        /// Validates the and store parameters.
        /// </summary>
        /// <param name="resourcePathName">Name of the resource path.</param>
        private void ValidateAndStoreParameters(string resourcePathName)
        {
            Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(resourcePathName), "resourcePathName could not be null or empty.");

            // check that the path name represents a valid path
            DirectoryInfo directoryInfo = new DirectoryInfo(resourcePathName);
            if (!directoryInfo.Exists)
                throw new InvalidSystemConfigurationException(
                    string.Format("The path name {0} is invalid or not exists.", resourcePathName)
                );

            // store the path name
            this.resourcePathName = resourcePathName;

            // Check for a valid base name by looking for the neutral or invariant resource file
            FileInfo fileInfo = new FileInfo(ResourceFileName.Build(resourcePathName, ResourceBaseName, null, FindFileResourceExtension()));
            if (!fileInfo.Exists)
                throw new InvalidSystemConfigurationException(
                    String.Format("The base name {0} is invalid or not exists, no invariant file was found with this name.", ResourceBaseName));
        }

        #endregion
    }
}
